# Este módulo maneja la autenticación del usuario al sistema.
module AuthenticatedSystem

  protected
    # Devuelve verdadero si hay un usuario logueado al sistema, y false en caso contrario.
    def logged_in?
      !!current_user
    end

    # Provee el acceso al usuario actual logueado.
    def current_user
      @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_user == false
    end

    # Guarda el id del usuario actual en la sesión.
    def current_user=(new_user)
      session[:user_id] = new_user ? new_user.id : nil
      @current_user = new_user || false
    end

    # Valida que el usuario este autoizado
    def authorized?
      logged_in?
    end

    # Permite filtrar el acceso a partes del sistema, cuando no hay un usuario logueado.
    def login_required
      authorized? || access_denied
    end

    # En caso de que el usuario no tenga acceso, redirecciona a donde corresponda.
    def access_denied
      respond_to do |format|
        format.html do
          store_location
          redirect_to new_session_path
        end
        format.any do
          request_http_basic_authentication 'Web Password'
        end
      end
    end

    # Guarda la ultima sesión activa.
    def store_location
      session[:return_to] = request.request_uri
    end

    # Redirecciona a la ultima dirección activa guardada, o la predeterminada.
    def redirect_back_or_default(default)
      redirect_to(session[:return_to] || default)
      session[:return_to] = nil
    end

    # Inclusión para hacer que #current_user y #logged_in estén disponibles como métodos del ActionView.
    def self.included(base)
      base.send :helper_method, :current_user, :logged_in?
    end

    # Llamado desde #current_user. Primer intento, loguease a través del usuario guardado en la sesión.
    def login_from_session
      self.current_user = User.find_by_id(session[:user_id]) if session[:user_id]
    end

    # Llamado desde #current_user. Segundo intento, loguearse a través de la autenticación básica. 
    def login_from_basic_auth
      authenticate_with_http_basic do |username, password|
        self.current_user = User.authenticate(username, password)
      end
    end

    # Llamado desde #current_user. Como último intento, como un token expirado en la cookie.
    def login_from_cookie
      user = cookies[:auth_token] && User.find_by_remember_token(cookies[:auth_token])
      if user && user.remember_token?
        cookies[:auth_token] = { :value => user.remember_token, :expires => user.remember_token_expires_at }
        self.current_user = user
      end
    end
end
